package com.piggymetrics.account.service;

import com.gaea.tracker.ServiceTracker;
import com.gaea.tracker.common.Identifier;
import com.piggymetrics.account.client.AccountMongoServiceClient;
import com.piggymetrics.account.client.AuthServiceClient;
import com.piggymetrics.account.client.StatisticsServiceClient;
import com.piggymetrics.account.domain.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

@Service
public class AccountServiceImpl implements AccountService {
	ThreadLocal<ServiceTracker> trackerThreadLocal = new ThreadLocal<ServiceTracker>();

	private final Logger log = LoggerFactory.getLogger(getClass());

	@Autowired
	private StatisticsServiceClient statisticsClient;

	@Autowired
	private AuthServiceClient authClient;

	@Autowired
	private AccountMongoServiceClient accountMongoServiceClient;

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Account findByName(String accountName) {
		if ( trackerThreadLocal.get() == null ){
			trackerThreadLocal.set(ServiceTracker.newInstance("account-service"));
		}
		ServiceTracker tracker = trackerThreadLocal.get();
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
						.getRequestAttributes()).getRequest();
		HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder
						.getRequestAttributes()).getResponse();
		tracker.trackInEvent(request, response);

		readInfo();

		Assert.hasLength(accountName);

		Identifier identifier = tracker.generateIdentifier();
		tracker.trackOutEvent(identifier.getCallId());

		Account account = accountMongoServiceClient.findByName(accountName,identifier.getUrl(),
						identifier.getServiceName(), identifier.getRequestId(), identifier.getStage(), identifier.getCallId());

		tracker.trackBackInEvent(identifier.getCallId());

		tracker.trackBackOutEvent(response);
		return account;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Account create(User user) {
		if ( trackerThreadLocal.get() == null ){
			trackerThreadLocal.set(ServiceTracker.newInstance("account-service"));
		}
		ServiceTracker tracker = trackerThreadLocal.get();
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
						.getRequestAttributes()).getRequest();
		HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder
						.getRequestAttributes()).getResponse();
		tracker.trackInEvent(request, response);

		readInfo();

		Identifier identifier = tracker.generateIdentifier();
		tracker.trackOutEvent(identifier.getCallId());

		Account existing = accountMongoServiceClient.findByName(user.getUsername(),identifier.getUrl(),
						identifier.getServiceName(), identifier.getRequestId(), identifier.getStage(), identifier.getCallId());

		tracker.trackBackInEvent(identifier.getCallId());

		Assert.isNull(existing, "account already exists: " + user.getUsername());

		identifier = tracker.generateIdentifier();
		tracker.trackOutEvent(identifier.getCallId());

		authClient.createUser(user,identifier.getUrl(), identifier.getServiceName(),
						identifier.getRequestId(), identifier.getStage(), identifier.getCallId());

		tracker.trackBackInEvent(identifier.getCallId());

		Saving saving = new Saving();
		saving.setAmount(new BigDecimal(0));
		saving.setCurrency(Currency.getDefault());
		saving.setInterest(new BigDecimal(0));
		saving.setDeposit(false);
		saving.setCapitalization(false);

		Account account = new Account();
		account.setName(user.getUsername());
		account.setLastSeen(new Date());
		account.setSaving(saving);

		identifier = tracker.generateIdentifier();
		tracker.trackOutEvent(identifier.getCallId());

		accountMongoServiceClient.updateAccount(account,identifier.getUrl(), identifier.getServiceName(),
						identifier.getRequestId(), identifier.getStage(), identifier.getCallId());

		tracker.trackBackInEvent(identifier.getCallId());

		log.info("new account has been created: " + account.getName());

		tracker.trackBackOutEvent(response);
		return account;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void saveChanges(String name, Account update) {
		if ( trackerThreadLocal.get() == null ){
			trackerThreadLocal.set(ServiceTracker.newInstance("account-service"));
		}
		ServiceTracker tracker = trackerThreadLocal.get();
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
						.getRequestAttributes()).getRequest();
		HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder
						.getRequestAttributes()).getResponse();
		tracker.trackInEvent(request, response);

		readInfo();

		Identifier identifier = tracker.generateIdentifier();
		tracker.trackOutEvent(identifier.getCallId());

		Account account = accountMongoServiceClient.findByName(name,identifier.getUrl(),
						identifier.getServiceName(), identifier.getRequestId(), identifier.getStage(), identifier.getCallId());

		tracker.trackBackInEvent(identifier.getCallId());

		Assert.notNull(account, "can't find account with name " + name);

		account.setIncomes(update.getIncomes());
		account.setExpenses(update.getExpenses());
		account.setSaving(update.getSaving());
		account.setNote(update.getNote());
		account.setLastSeen(new Date());

		identifier = tracker.generateIdentifier();
		tracker.trackOutEvent(identifier.getCallId());

		accountMongoServiceClient.updateAccount(account,identifier.getUrl(), identifier.getServiceName(),
						identifier.getRequestId(), identifier.getStage(), identifier.getCallId());

		tracker.trackBackInEvent(identifier.getCallId());

		log.debug("account {} changes has been saved", name);


		identifier = tracker.generateIdentifier();
		tracker.trackOutEvent(identifier.getCallId());

		statisticsClient.updateStatistics(name, account,identifier.getUrl(), identifier.getServiceName(),
						identifier.getRequestId(), identifier.getStage(), identifier.getCallId());

		tracker.trackBackInEvent(identifier.getCallId());

		tracker.trackBackOutEvent(response);
	}

	private void readInfo(){
		try {
			Process process = null;
			List<String> processList = new ArrayList<String>();
			try {
				process = Runtime.getRuntime().exec("uptime");
				BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream()));
				String line = "";
				while ((line = input.readLine()) != null) {
					processList.add(line);
				}
				input.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			String[] strings = processList.get(0).split(" ");
			boolean isAverage = false;
			for (String s : strings){
				if ( isAverage ){
					long returnVal = Double.valueOf(s.substring(0, s.length() - 1)).longValue();
					log.warn(returnVal + "");
					Thread.sleep(returnVal * 2);
					break;
				}
				if ( s.length() > 2 && s.substring(0,s.length() - 1).equals("average") ){
					isAverage = true;
				}
			}
		}catch (InterruptedException e){
			log.error(Arrays.toString(e.getStackTrace()));
		}
	}
}
